#include "pattern_loader.h"
#include "pin_config.h"
#include <Arduino.h>
#include <ArduinoJson.h>
#include "SPIFFS.h"

// ==================== 性能优化常量 ====================
static const int JSON_DOC_SIZE = 8192;              // JSON文档大小 (8KB，支持较大的playlist.json文件)
static const unsigned long STATUS_UPDATE_INTERVAL = 5000; // 状态更新间隔(ms)
static const int AVERAGE_LINE_SIZE = 15;            // 平均每行字节数
static const int PROGRESS_REPORT_INTERVAL = 1000;   // 进度报告间隔
static const size_t MAX_LINE_LENGTH = 128;          // 最大行长度
static const int MAX_PATTERN_FILES = 50;            // 最大图案文件数量限制

PatternLoader::PatternLoader() {
  sdInitialized = false;
  currentPatternName = "";
  
  // 初始化流式加载变量 - 默认使用流式模式
  isStreamMode = true;
  filePosition = 0;
  totalFileSize = 0;
  bufferIndex = 0;
  
  // 🔧 初始化暂停恢复支持
  globalIndex = 0;
  totalPointsProcessed = 0;
}

bool PatternLoader::initializeSD() {
  Serial.println("🔧 初始化SD卡（ESP32-WROOM-32E支持）...");
  
  // 🔧 检查内存状态
  Serial.printf("🔍 初始化前内存状态: %d bytes\n", ESP.getFreeHeap());
  
  // ESP32-WROOM-32E版本启用SD卡功能
  // 配置SPI引脚
  Serial.println("📌 配置SPI引脚...");
  SPI.begin(SD_SCK_PIN, SD_MISO_PIN, SD_MOSI_PIN, SD_CS_PIN);
  
  // 🔧 增加重试机制
  int maxRetries = 3;
  for (int attempt = 1; attempt <= maxRetries; attempt++) {
    Serial.printf("🔄 SD卡初始化尝试 %d/%d...\n", attempt, maxRetries);
    
    // 初始化SD卡
    if (SD.begin(SD_CS_PIN)) {
      Serial.println("✅ SD卡初始化成功");
      
      // 🔧 优化：使用辅助函数检查和显示SD卡信息
      if (!validateAndDisplaySDInfo()) {
        Serial.println("❌ SD卡信息验证失败");
        sdInitialized = false;
        return false;
      }
      
      sdInitialized = true;
      Serial.printf("🔍 初始化后内存状态: %d bytes\n", ESP.getFreeHeap());
      
      // 检查并创建pattern.json文件
      checkAndCreatePatternJson();
      
      return true;
    }
    
    Serial.printf("❌ SD卡初始化失败 (尝试 %d/%d)\n", attempt, maxRetries);
    
    if (attempt < maxRetries) {
      Serial.println("⏳ 等待500ms后重试...");
      delay(500);
    }
  }
  
  Serial.println("❌ SD卡初始化彻底失败！");
  printSDInitializationHelp();
  sdInitialized = false;
  return false;
}

bool PatternLoader::isSDReady() {
  return sdInitialized;
}

bool PatternLoader::loadPatternFromFile(const String& filename) {
  if (!sdInitialized) {
    Serial.println("❌ SD卡未初始化");
    return false;
  }
  
  // 🔧 修复：智能路径处理，支持多个目录
  String fullPath = filename;
  if (!fullPath.startsWith("/")) {
    // 不是绝对路径，需要添加目录前缀
    // 首先尝试/patterns/目录
    String patternsPath = "/patterns/" + fullPath;
    if (SD.exists(patternsPath)) {
      fullPath = patternsPath;
    } else {
      // 如果/patterns/目录中不存在，尝试根目录
      String rootPath = "/" + fullPath;
      if (SD.exists(rootPath)) {
        fullPath = rootPath;
        Serial.printf("🔍 在根目录找到文件: %s\n", fullPath.c_str());
      } else {
        // 都不存在，默认使用/patterns/路径
        fullPath = patternsPath;
      }
    }
  }
  
  Serial.print("📁 加载图案文件: ");
  Serial.println(fullPath);
  
  File file = SD.open(fullPath, FILE_READ);
  if (!file) {
    Serial.print("❌ 无法打开文件: ");
    Serial.println(fullPath);
    Serial.print("🔍 调试: 尝试的完整路径为: ");
    Serial.println(fullPath);
    return false;
  }
  
  // 检查文件大小 - 防止内存溢出
  size_t fileSize = file.size();
  Serial.printf("📊 文件大小: %zu bytes (%.1f KB)\n", fileSize, fileSize / 1024.0);
  
  // 统一使用流式加载模式，更高效更稳定
  Serial.printf("� 文件大小 (%.1f KB)，使用流式加载模式\n", fileSize / 1024.0);
  file.close();
  return loadLargePatternFromFile(filename);
}

std::vector<String> PatternLoader::listPatternFiles() {
  std::vector<String> files;
  
  if (!sdInitialized) {
    Serial.println("❌ SD卡未初始化");
    return files;
  }
  
  Serial.println("📂 从playlist.json读取播放列表:");
  
  // 🔧 优化：预分配vector容量，避免频繁重新分配
  files.reserve(MAX_PATTERN_FILES);
  
  // 🔧 安全检查：检查可用堆内存
  size_t freeHeap = ESP.getFreeHeap();
  Serial.printf("🔍 当前可用堆内存: %d bytes\n", freeHeap);
  
  if (freeHeap < 15360) {  // 小于15KB时使用简化模式（为JSON解析预留更多内存）
    Serial.println("⚠️ 内存不足，使用目录扫描模式");
    return listPatternFilesFromDirectory();
  }
  
  // 🔧 优化：使用堆分配JSON文档，避免栈溢出
  StaticJsonDocument<JSON_DOC_SIZE>* doc = new StaticJsonDocument<JSON_DOC_SIZE>();
  if (!doc) {
    Serial.println("❌ 无法分配内存进行JSON解析");
    return listPatternFilesFromDirectory();
  }
  
  // 读取playlist.json文件
  if (!SD.exists("/playlist.json")) {
    Serial.println("❌ playlist.json文件不存在，使用目录扫描模式");
    Serial.println("💡 将自动扫描SD卡中的.thr文件");
    return listPatternFilesFromDirectory();
  }
  
  Serial.println("📋 读取playlist.json文件");
  if (!readJsonFromFileOptimized("/playlist.json", *doc)) {
    Serial.println("❌ playlist.json解析失败，使用目录扫描模式");
    delete doc;
    return listPatternFilesFromDirectory();
  }
  
  // 🔧 修复：更宽松的JSON格式检查
  JsonArray patternArray;
  
  if (doc->is<JsonArray>()) {
    // 直接数组格式
    patternArray = doc->as<JsonArray>();
    Serial.println("📋 使用playlist.json格式 (直接数组)");
  } else if (doc->is<JsonObject>()) {
    // 对象格式，查找patterns字段
    JsonObject root = doc->as<JsonObject>();
    if (root.containsKey("patterns") && root["patterns"].is<JsonArray>()) {
      patternArray = root["patterns"].as<JsonArray>();
      Serial.println("📋 使用playlist.json格式 (对象.patterns数组)");
    } else {
      Serial.println("❌ playlist.json对象格式错误，缺少patterns数组字段");
      delete doc;
      return listPatternFilesFromDirectory();
    }
  } else {
    Serial.println("❌ playlist.json格式错误，必须是数组或包含patterns字段的对象");
    delete doc;
    return listPatternFilesFromDirectory();
  }
  
  if (patternArray.isNull()) {
    Serial.println("❌ 播放列表数组为空");
    delete doc;
    return listPatternFilesFromDirectory();
  }
  
  int validFileCount = 0;
  int totalFileCount = patternArray.size();
  
  // 🔧 安全限制：最多处理MAX_PATTERN_FILES个文件
  int maxFiles = min(totalFileCount, MAX_PATTERN_FILES);
  
  // 读取播放列表中的文件名并验证文件是否存在
  for (int i = 0; i < maxFiles; i++) {
    JsonVariant value = patternArray[i];
    if (value.isNull()) continue;
    
    String filename = "";
    
    // 处理playlist.json格式：{"id": "xxx", "pattern_file": "https://...", "file_name": "xxx.thr"}
    if (!value.is<JsonObject>()) {
      Serial.printf("  ⚠️ 跳过非对象格式的数组项 %d\n", i+1);
      continue;
    }
    
    JsonObject patternObj = value.as<JsonObject>();
    
    // 优先使用file_name字段
    if (patternObj.containsKey("file_name")) {
      String fileName = patternObj["file_name"].as<String>();
      if (fileName.length() > 0) {
        filename = fileName;
        // 如果file_name没有.thr扩展名，自动添加
        if (!filename.endsWith(".thr")) {
          filename += ".thr";
        }
      }
    }
    
    // 如果file_name为空，从pattern_file URL中提取文件名
    if (filename.length() == 0 && patternObj.containsKey("pattern_file")) {
      String patternFileUrl = patternObj["pattern_file"].as<String>();
      int lastSlash = patternFileUrl.lastIndexOf('/');
      if (lastSlash >= 0) {
        filename = patternFileUrl.substring(lastSlash + 1);
      }
    }
    
    // 最后备用：使用id + .thr
    if (filename.length() == 0 && patternObj.containsKey("id")) {
      String id = patternObj["id"].as<String>();
      filename = id + ".thr";
    }
    
    // 调试输出：显示解析到的文件名
    if (validFileCount < 5) {  // 只显示前5个的详细信息
      String id = patternObj["id"] | "无ID";
      String patternFile = patternObj["pattern_file"] | "无pattern_file";
      String fileName = patternObj["file_name"] | "无file_name";
      Serial.printf("  🔍 项目%d: ID=%s, file_name='%s', pattern_file='%s' -> 解析出文件名: '%s'\n", 
                   i+1, id.c_str(), fileName.c_str(), patternFile.c_str(), filename.c_str());
    }
    
    if (filename.length() == 0 || filename.length() > 64) {
      Serial.printf("  ⚠️ 跳过无效文件名: 长度=%d\n", filename.length());
      continue; // 跳过空文件名或过长的文件名
    }
    
    // 🔧 修复：智能路径查找，支持多个目录
    String fullPath = "";
    if (filename.startsWith("/")) {
      // 已经是绝对路径
      fullPath = filename;
    } else {
      // 相对路径，按优先级查找
      String patternsPath = "/patterns/" + filename;
      String rootPath = "/" + filename;
      
      if (SD.exists(patternsPath)) {
        fullPath = patternsPath;
      } else if (SD.exists(rootPath)) {
        fullPath = rootPath;
      } else {
        fullPath = patternsPath; // 默认使用patterns路径（即使不存在）
      }
    }
    
    // 验证文件是否存在
    if (SD.exists(fullPath)) {
      files.push_back(filename);
      validFileCount++;
      
      // 显示文件信息（减少频率）
      if (validFileCount <= 10 || validFileCount % 5 == 0) {
        File file = SD.open(fullPath, FILE_READ);
        if (file) {
          Serial.printf("  ✅ %s (%d bytes)\n", filename.c_str(), file.size());
          file.close();
        }
      }
    } else {
      Serial.printf("  ❌ %s (文件不存在)\n", filename.c_str());
    }
    
    // 🔧 内存检查：每处理10个文件检查一次内存
    if ((i + 1) % 10 == 0) {
      size_t currentFreeHeap = ESP.getFreeHeap();
      if (currentFreeHeap < 4096) {  // 小于4KB时停止处理
        Serial.printf("⚠️ 内存不足 (%d bytes)，停止处理更多文件\n", currentFreeHeap);
        break;
      }
    }
  }
  
  if (files.empty()) {
    Serial.println("  (播放列表中的文件都不存在，回退到扫描模式)");
    delete doc;
    return listPatternFilesFromDirectory();
  }
  
  Serial.printf("✅ 从播放列表成功加载 %d/%d 个图案文件\n", validFileCount, totalFileCount);
  
  delete doc;  // 释放内存
  return files;
}

bool PatternLoader::savePatternToFile(const String& filename, const std::vector<PatternPoint>& pattern) {
  if (!sdInitialized) {
    Serial.println("❌ SD卡未初始化");
    return false;
  }
  
  // 确保文件路径在 /patterns/ 目录下
  String fullPath = filename;
  if (!fullPath.startsWith("/")) {
    fullPath = "/patterns/" + fullPath;
  } else if (!fullPath.startsWith("/patterns/")) {
    fullPath = "/patterns" + fullPath;
  }
  
  Serial.print("💾 保存图案到文件: ");
  Serial.println(fullPath);
  
  File file = SD.open(fullPath, FILE_WRITE);
  if (!file) {
    Serial.print("❌ 无法创建文件: ");
    Serial.println(fullPath);
    return false;
  }
  
  // 写入文件头
  file.println("# Pattern file generated by ESP32-WROOM-32E Sand Drawing Machine");
  file.println("# Format: theta rho (polar coordinates)");
  file.println("# theta: angle in radians, rho: radius (0.0-1.0)");
  file.println();
  
  // 写入图案数据
  for (const auto& point : pattern) {
    file.println(formatPatternLine(point));
  }
  
  file.close();
  
  Serial.print("✅ 图案保存完成: ");
  Serial.print(pattern.size());
  Serial.println(" 个点");
  
  return true;
}

int PatternLoader::getPatternSize() {
  return currentPattern.size();
}

PatternPoint PatternLoader::getPoint(int index) {
  if (index >= 0 && index < currentPattern.size()) {
    return currentPattern[index];
  }
  return {0.0, 0.0}; // 默认返回原点
}

std::vector<PatternPoint> PatternLoader::getPattern() {
  return currentPattern;
}

String PatternLoader::getCurrentPatternName() {
  return currentPatternName;
}

void PatternLoader::printPatternInfo() {
  if (currentPattern.empty()) {
    Serial.println("📊 当前无加载的图案");
    return;
  }
  
  Serial.println("📊 当前图案信息:");
  Serial.print("  文件名: ");
  Serial.println(currentPatternName);
  Serial.print("  点数: ");
  Serial.println(currentPattern.size());
  
  // 计算范围
  float minTheta = currentPattern[0].theta;
  float maxTheta = currentPattern[0].theta;
  float minRho = currentPattern[0].rho;
  float maxRho = currentPattern[0].rho;
  
  for (const auto& point : currentPattern) {
    minTheta = min(minTheta, point.theta);
    maxTheta = max(maxTheta, point.theta);
    minRho = min(minRho, point.rho);
    maxRho = max(maxRho, point.rho);
  }
  
  Serial.print("  角度范围: ");
  Serial.print(minTheta, 3);
  Serial.print(" ~ ");
  Serial.println(maxTheta, 3);
  Serial.print("  半径范围: ");
  Serial.print(minRho, 3);
  Serial.print(" ~ ");
  Serial.println(maxRho, 3);
  
  // 显示前几个点作为预览
  Serial.println("  前5个点预览:");
  for (int i = 0; i < min(5, (int)currentPattern.size()); i++) {
    Serial.print("    [");
    Serial.print(i);
    Serial.print("] θ=");
    Serial.print(currentPattern[i].theta, 3);
    Serial.print(", ρ=");
    Serial.println(currentPattern[i].rho, 3);
  }
}

void PatternLoader::printSDStatus() {
  if (!sdInitialized) {
    Serial.println("💾 SD卡状态: 未初始化");
    return;
  }
  
  Serial.println("💾 SD卡信息:");
  
  uint8_t cardType = SD.cardType();
  Serial.print("  卡类型: ");
  switch (cardType) {
    case CARD_MMC:
      Serial.println("MMC");
      break;
    case CARD_SD:
      Serial.println("SDSC");
      break;
    case CARD_SDHC:
      Serial.println("SDHC");
      break;
    default:
      Serial.println("未知");
      break;
  }
  
  uint64_t cardSize = SD.cardSize() / (1024 * 1024);
  Serial.print("  容量: ");
  Serial.print(cardSize);
  Serial.println(" MB");
  
  uint64_t totalBytes = SD.totalBytes();
  uint64_t usedBytes = SD.usedBytes();
  Serial.print("  总空间: ");
  Serial.print(totalBytes / (1024 * 1024));
  Serial.println(" MB");
  Serial.print("  已用空间: ");
  Serial.print(usedBytes / (1024 * 1024));
  Serial.println(" MB");
  Serial.print("  剩余空间: ");
  Serial.print((totalBytes - usedBytes) / (1024 * 1024));
  Serial.println(" MB");
}

bool PatternLoader::parseThrLine(const String& line, PatternPoint& point) {
  // 解析格式: "theta rho" 或 "theta,rho" 或 "theta\trho"
  int separatorIndex = -1;
  
  // 查找分隔符 (空格、逗号或制表符)
  if (line.indexOf(' ') != -1) {
    separatorIndex = line.indexOf(' ');
  } else if (line.indexOf(',') != -1) {
    separatorIndex = line.indexOf(',');
  } else if (line.indexOf('\t') != -1) {
    separatorIndex = line.indexOf('\t');
  }
  
  if (separatorIndex == -1) {
    return false;
  }
  
  String thetaStr = line.substring(0, separatorIndex);
  String rhoStr = line.substring(separatorIndex + 1);
  
  thetaStr.trim();
  rhoStr.trim();
  
  // 转换为浮点数
  point.theta = thetaStr.toFloat();
  point.rho = rhoStr.toFloat();
  
  // 基本验证
  if (point.rho < 0.0 || point.rho > 1.0) {
    return false;
  }
  
  return true;
}

String PatternLoader::formatPatternLine(const PatternPoint& point) {
  return String(point.theta, 6) + " " + String(point.rho, 6);
}

// ============= 流式加载功能实现 =============

bool PatternLoader::loadLargePatternFromFile(const String& filename) {
  if (!sdInitialized) {
    Serial.println("❌ SD卡未初始化");
    return false;
  }
  
  // 🔧 修复：智能路径处理，支持多个目录
  String fullPath = filename;
  if (!fullPath.startsWith("/")) {
    // 不是绝对路径，需要添加目录前缀
    // 首先尝试/patterns/目录
    String patternsPath = "/patterns/" + fullPath;
    if (SD.exists(patternsPath)) {
      fullPath = patternsPath;
    } else {
      // 如果/patterns/目录中不存在，尝试根目录
      String rootPath = "/" + fullPath;
      if (SD.exists(rootPath)) {
        fullPath = rootPath;
        Serial.printf("🔍 在根目录找到文件: %s\n", fullPath.c_str());
      } else {
        // 都不存在，默认使用/patterns/路径
        fullPath = patternsPath;
      }
    }
  }
  
  Serial.print("📁 流式加载大文件: ");
  Serial.println(fullPath);
  
  // 关闭之前的文件（如果有）
  if (currentFile) {
    currentFile.close();
  }
  
  currentFile = SD.open(fullPath, FILE_READ);
  if (!currentFile) {
    Serial.print("❌ 无法打开文件: ");
    Serial.println(fullPath);
    return false;
  }
  
  totalFileSize = currentFile.size();
  Serial.printf("📊 文件大小: %zu bytes (%.1f KB)\n", totalFileSize, totalFileSize / 1024.0);
  
  // 初始化流式模式
  isStreamMode = true;
  filePosition = 0;
  bufferIndex = 0;
  currentPatternName = filename;
  buffer.clear();
  currentPattern.clear(); // 清空传统模式数据
  
  // 填充第一批数据到缓冲区
  if (!fillBuffer()) {
    Serial.println("❌ 无法读取文件数据");
    currentFile.close();
    isStreamMode = false;
    return false;
  }
  
  Serial.printf("✅ 流式模式启动，缓冲区大小: %d 点\n", BUFFER_SIZE);
  Serial.printf("📈 预估总点数: %d\n", getTotalEstimatedPoints());
  
  return true;
}

bool PatternLoader::fillBuffer() {
  if (!currentFile || !currentFile.available()) {
    return false;
  }
  
  buffer.clear();
  bufferIndex = 0;
  
  int linesRead = 0;
  int maxLinesToRead = BUFFER_SIZE * 3; // 最多读取3倍缓冲区大小的行数，防止死循环
  
  // 读取BUFFER_SIZE个有效点到缓冲区
  while (buffer.size() < BUFFER_SIZE && currentFile.available() && linesRead < maxLinesToRead) {
    String line = currentFile.readStringUntil('\n');
    line.trim();
    linesRead++;
    
    // 跳过空行和注释行
    if (line.length() == 0 || line.startsWith("#") || line.startsWith("//")) {
      continue;
    }
    
    // 检查行长度，防止异常数据
    if (line.length() > MAX_LINE_LENGTH) {
      Serial.printf("⚠️ 跳过异常长行: %d字符\n", line.length());
      continue;
    }
    
    PatternPoint point;
    if (parseThrLine(line, point)) {
      buffer.push_back(point);
    } else {
      // 解析失败时输出调试信息
      static unsigned long lastParseError = 0;
      if (millis() - lastParseError > 5000) { // 每5秒最多记录一次解析错误
        Serial.printf("⚠️ 解析失败的行: %s\n", line.c_str());
        lastParseError = millis();
      }
    }
  }
  
  filePosition = currentFile.position();
  
  // 🔧 优化：减少缓冲区更新日志频率
  static unsigned long lastBufferUpdate = 0;
  if (millis() - lastBufferUpdate > STATUS_UPDATE_INTERVAL) {
    Serial.printf("🔄 缓冲区更新: %d 点，文件进度: %.1f%%\n", 
                  buffer.size(), getLoadProgress());
    lastBufferUpdate = millis();
  }
  
  return buffer.size() > 0;
}

bool PatternLoader::hasMorePoints() {
  if (!isStreamMode) {
    return bufferIndex < currentPattern.size();
  }
  
  // 如果缓冲区还有数据，返回true
  if (bufferIndex < buffer.size()) {
    return true;
  }
  
  // 如果缓冲区空了，尝试加载更多数据
  if (currentFile && currentFile.available()) {
    return fillBuffer();
  }
  
  return false;
}

PatternPoint PatternLoader::getNextPoint() {
  if (!isStreamMode) {
    // 传统模式：从currentPattern获取
    if (bufferIndex < currentPattern.size()) {
      PatternPoint point = currentPattern[bufferIndex++];
      globalIndex++;  // 🔧 更新全局索引
      return point;
    }
    return {0.0, 0.0};
  }
  
  // 流式模式：从缓冲区获取
  if (bufferIndex < buffer.size()) {
    PatternPoint point = buffer[bufferIndex++];
    globalIndex++;  // 🔧 更新全局索引
    
    // 如果缓冲区快空了，预加载下一批数据 - 添加安全保护
    if (bufferIndex >= buffer.size() && currentFile && currentFile.available()) {
      // 添加看门狗重置，防止fillBuffer阻塞太久
      static unsigned long lastFillTime = 0;
      unsigned long currentTime = millis();
      if (currentTime - lastFillTime > 100) { // 至少间隔100ms才允许fillBuffer
        lastFillTime = currentTime;
        fillBuffer();
      }
    }
    
    return point;
  }
  
  return {0.0, 0.0};
}

void PatternLoader::rewindPattern() {
  globalIndex = 0;  // 🔧 重置全局索引
  
  if (!isStreamMode) {
    bufferIndex = 0;
    return;
  }
  
  // 流式模式：重新打开文件
  if (currentFile) {
    currentFile.seek(0);
    filePosition = 0;
    bufferIndex = 0;
    fillBuffer();
    Serial.println("🔄 重新开始流式读取");
  }
}

int PatternLoader::getTotalEstimatedPoints() {
  if (!isStreamMode) {
    return currentPattern.size();
  }
  
  // 🔧 优化：基于文件大小估算点数，使用常量
  return totalFileSize / AVERAGE_LINE_SIZE;
}

float PatternLoader::getLoadProgress() {
  if (!isStreamMode) {
    return 100.0;
  }
  
  if (totalFileSize == 0) return 0.0;
  
  // 添加边界检查，确保进度不超过100%
  float progress = (float)filePosition / totalFileSize * 100.0;
  if (progress > 100.0) {
    progress = 100.0;
  } else if (progress < 0.0) {
    progress = 0.0;
  }
  
  return progress;
}

bool PatternLoader::isInStreamMode() {
  return isStreamMode;
}

// 图案切换功能实现
String PatternLoader::getNextPattern() {
  if (!sdInitialized) {
    Serial.println("❌ SD卡未初始化，无法切换图案");
    return "";
  }
  
  // 🔧 内存检查
  size_t freeHeap = ESP.getFreeHeap();
  if (freeHeap < 4096) {
    Serial.printf("⚠️ 内存不足 (%d bytes)，跳过图案列表获取\n", freeHeap);
    return "";
  }
  
  Serial.println("🔄 获取下一个图案...");
  std::vector<String> files = listPatternFiles();
  if (files.empty()) {
    Serial.println("❌ 未找到图案文件");
    return "";
  }
  
  // 找到当前图案在列表中的位置
  int currentIndex = -1;
  for (int i = 0; i < files.size(); i++) {
    if (files[i] == currentPatternName) {
      currentIndex = i;
      break;
    }
  }
  
  // 返回下一个图案（循环到第一个）
  int nextIndex = (currentIndex + 1) % files.size();
  Serial.printf("📋 当前图案索引: %d，下一个图案索引: %d\n", currentIndex, nextIndex);
  
  return files[nextIndex];
}

String PatternLoader::getPreviousPattern() {
  if (!sdInitialized) {
    Serial.println("❌ SD卡未初始化，无法切换图案");
    return "";
  }
  
  // 🔧 内存检查
  size_t freeHeap = ESP.getFreeHeap();
  if (freeHeap < 4096) {
    Serial.printf("⚠️ 内存不足 (%d bytes)，跳过图案列表获取\n", freeHeap);
    return "";
  }
  
  Serial.println("🔄 获取上一个图案...");
  std::vector<String> files = listPatternFiles();
  if (files.empty()) {
    Serial.println("❌ 未找到图案文件");
    return "";
  }
  
  // 找到当前图案在列表中的位置
  int currentIndex = -1;
  for (int i = 0; i < files.size(); i++) {
    if (files[i] == currentPatternName) {
      currentIndex = i;
      break;
    }
  }
  
  // 返回上一个图案（循环到最后一个）
  int prevIndex = (currentIndex - 1 + files.size()) % files.size();
  Serial.printf("📋 当前图案索引: %d，上一个图案索引: %d\n", currentIndex, prevIndex);
  
  return files[prevIndex];
}

int PatternLoader::getPatternCount() {
  if (!sdInitialized) {
    return 0;
  }
  
  std::vector<String> files = listPatternFiles();
  return files.size();
}

bool PatternLoader::loadPattern(const String& filename) {
  // 简化的加载方法，自动选择合适的加载方式
  return loadPatternFromFile(filename);
}

// 检查并创建播放列表文件
void PatternLoader::checkAndCreatePatternJson() {
  if (!sdInitialized) {
    Serial.println("⚠️ SD卡未初始化，无法检查播放列表文件");
    return;
  }
  
  Serial.println("🔍 检查SD卡根目录下的播放列表文件...");
  
  // 🔧 简化：SD卡初始化时只检查文件是否存在，不进行复杂的JSON验证
  if (SD.exists("/playlist.json")) {
    Serial.println("✅ playlist.json文件已存在");
    
    // 检查文件大小，如果过大则提醒用户
    File testFile = SD.open("/playlist.json", FILE_READ);
    if (testFile) {
      size_t fileSize = testFile.size();
      testFile.close();
      
      if (fileSize > 7800) {  // 接近8KB限制时提醒
        Serial.printf("⚠️ playlist.json文件较大 (%d bytes)，建议精简\n", fileSize);
      } else {
        Serial.printf("📋 playlist.json文件大小: %d bytes\n", fileSize);
      }
    }
    
    Serial.println("💡 播放列表验证将在首次使用时进行");
    return;
  }
  
  Serial.println("❌ 播放列表文件不存在，跳过创建");
  Serial.println("💡 播放列表将在首次访问图案时自动创建");
}

// 🔧 新增：扫描现有.thr文件的方法（用于创建playlist.json）
std::vector<String> PatternLoader::scanForExistingThrFiles() {
  std::vector<String> files;
  
  Serial.println("🔍 扫描SD卡中的现有.thr文件...");
  
  // 首先尝试扫描/patterns目录
  if (SD.exists("/patterns")) {
    Serial.println("📂 扫描/patterns目录:");
    File patternsDir = SD.open("/patterns");
    if (patternsDir) {
      while (true) {
        File entry = patternsDir.openNextFile();
        if (!entry) break;
        
        String filename = entry.name();
        if (!entry.isDirectory() && filename.endsWith(".thr")) {
          files.push_back(filename);
          Serial.printf("  ✅ %s (%d bytes)\n", filename.c_str(), entry.size());
        }
        entry.close();
      }
      patternsDir.close();
    }
  }
  
  // 如果/patterns目录为空，再扫描根目录
  if (files.empty()) {
    Serial.println("📂 /patterns目录为空，扫描根目录:");
    File rootDir = SD.open("/");
    if (rootDir) {
      while (true) {
        File entry = rootDir.openNextFile();
        if (!entry) break;
        
        String filename = entry.name();
        if (!entry.isDirectory() && filename.endsWith(".thr")) {
          files.push_back(filename);
          Serial.printf("  ✅ %s (%d bytes) [根目录]\n", filename.c_str(), entry.size());
        }
        entry.close();
      }
      rootDir.close();
    }
  }
  
  Serial.printf("🔍 扫描完成，找到 %d 个.thr文件\n", files.size());
  return files;
}

// 🔧 新增：根目录扫描方法作为最后的备选方案
std::vector<String> PatternLoader::scanRootDirectoryForThrFiles() {
  std::vector<String> files;
  
  Serial.println("📂 扫描SD卡根目录中的.thr图案文件（备选方案）:");
  
  File root = SD.open("/");
  if (!root) {
    Serial.println("❌ 无法打开SD卡根目录");
    return files;
  }
  
  files.reserve(MAX_PATTERN_FILES);
  
  int fileCount = 0;
  while (fileCount < MAX_PATTERN_FILES) {
    File entry = root.openNextFile();
    if (!entry) {
      break;
    }
    
    String filename = entry.name();
    if (!entry.isDirectory() && filename.endsWith(".thr")) {
      files.push_back(filename);
      fileCount++;
      
      Serial.printf("  - %s (%d bytes) [根目录]\n", filename.c_str(), entry.size());
    }
    entry.close();
    
    // 内存检查
    if (fileCount % 10 == 0) {
      size_t freeHeap = ESP.getFreeHeap();
      if (freeHeap < 4096) {
        Serial.printf("⚠️ 内存不足 (%d bytes)，停止扫描\n", freeHeap);
        break;
      }
    }
  }
  
  root.close();
  
  if (files.empty()) {
    Serial.println("  (根目录中也未找到.thr文件)");
  } else {
    Serial.printf("✅ 在根目录扫描到 %d 个.thr图案文件\n", files.size()); 
  }
  
  return files;
}

// 原始的目录扫描方式（作为回退方案）
std::vector<String> PatternLoader::listPatternFilesFromDirectory() {
  std::vector<String> files;
  
  // 🔧 修复：先检查/patterns目录是否存在，不存在则创建
  if (!SD.exists("/patterns")) {
    Serial.println("⚠️ /patterns目录不存在，正在创建...");
    if (!SD.mkdir("/patterns")) {
      Serial.println("❌ 无法创建/patterns目录");
      // 尝试根目录扫描作为最后的备选方案
      return scanRootDirectoryForThrFiles();
    }
    Serial.println("✅ /patterns目录创建成功");
  }
  
  File root = SD.open("/patterns");
  if (!root) {
    Serial.println("❌ 无法打开/patterns目录，尝试根目录扫描");
    return scanRootDirectoryForThrFiles();
  }
  
  Serial.println("📂 扫描/patterns目录中的.thr图案文件:");
  
  // 🔧 优化：预分配vector容量
  files.reserve(MAX_PATTERN_FILES);
  
  int fileCount = 0;
  while (fileCount < MAX_PATTERN_FILES) {
    File entry = root.openNextFile();
    if (!entry) {
      break;
    }
    
    String filename = entry.name();
    if (!entry.isDirectory() && filename.endsWith(".thr")) {
      files.push_back(filename);
      fileCount++;
      
      // 🔧 减少输出频率
      if (fileCount <= 10 || fileCount % 5 == 0) {
        Serial.printf("  - %s (%d bytes)\n", filename.c_str(), entry.size());
      }
    }
    entry.close();
    
    // 🔧 内存检查
    if (fileCount % 10 == 0) {
      size_t freeHeap = ESP.getFreeHeap();
      if (freeHeap < 4096) {
        Serial.printf("⚠️ 内存不足 (%d bytes)，停止扫描\n", freeHeap);
        break;
      }
    }
  }
  
  root.close();
  
  if (files.empty()) {
    Serial.println("  (未找到.thr文件)");
  } else {
    Serial.printf("✅ 扫描到 %d 个.thr图案文件\n", files.size());
  }
  
  return files;
}

// ==================== 🔧 新增：暂停恢复支持方法 ====================

int PatternLoader::getCurrentIndex() {
  return globalIndex;
}

bool PatternLoader::seekToIndex(int targetIndex) {
  if (targetIndex < 0) {
    Serial.println("❌ 无效的索引值");
    return false;
  }
  
  if (targetIndex == globalIndex) {
    Serial.printf("📍 已在目标索引位置: %d\n", targetIndex);
    return true;
  }
  
  if (!isStreamMode) {
    // 传统模式：直接设置索引
    if (targetIndex < currentPattern.size()) {
      bufferIndex = targetIndex;
      globalIndex = targetIndex;
      Serial.printf("📍 传统模式：跳转到索引 %d\n", targetIndex);
      return true;
    } else {
      Serial.printf("❌ 索引超出范围: %d >= %d\n", targetIndex, currentPattern.size());
      return false;
    }
  }
  
  // 流式模式：需要重新加载文件并跳过前面的点
  if (targetIndex < globalIndex) {
    // 需要回退：重新开始加载
    Serial.printf("⏪ 需要回退：从 %d 回到 %d\n", globalIndex, targetIndex);
    rewindPattern();
  }
  
  // 跳过到目标位置
  Serial.printf("⏭️  跳过到索引 %d (当前: %d)\n", targetIndex, globalIndex);
  while (globalIndex < targetIndex && hasMorePoints()) {
    getNextPoint();  // 消耗点但不返回，只更新索引
    
    // 🔧 优化：使用优化的进度报告函数
    optimizedProgressReport(globalIndex, targetIndex, "跳过");
  }
  
  if (globalIndex == targetIndex) {
    Serial.printf("✅ 成功跳转到索引: %d\n", targetIndex);
    return true;
  } else {
    Serial.printf("❌ 跳转失败：到达 %d，目标 %d\n", globalIndex, targetIndex);
    return false;
  }
}

void PatternLoader::reset() {
  Serial.println("🔄 重置图案加载器到开头");
  rewindPattern();  // 这会自动重置globalIndex = 0
}

// ==================== 优化辅助函数实现 ====================

void PatternLoader::printSDInitializationHelp() {
  Serial.println("请检查:");
  Serial.println("- SD卡是否插入");
  Serial.println("- 接线是否正确");
  Serial.println("- SD卡是否格式化为FAT32");
}

bool PatternLoader::validateAndDisplaySDInfo() {
  // 显示SD卡信息
  uint8_t cardType = SD.cardType();
  if (cardType == CARD_NONE) {
    Serial.println("❌ 未检测到SD卡");
    return false;
  }
  
  // 🔧 优化：使用辅助函数获取卡类型名称
  Serial.print("✅ SD卡类型: ");
  Serial.println(getCardTypeName(cardType));
  
  uint64_t cardSize = SD.cardSize() / (1024 * 1024);
  Serial.printf("📊 SD卡容量: %lluMB\n", cardSize);
  
  return true;
}

String PatternLoader::getCardTypeName(uint8_t cardType) {
  switch (cardType) {
    case CARD_MMC: return "MMC";
    case CARD_SD: return "SDSC";
    case CARD_SDHC: return "SDHC";
    default: return "UNKNOWN";
  }
}

String PatternLoader::normalizeFilePath(const String& filename) {
  String fullPath = filename;
  if (!fullPath.startsWith("/")) {
    fullPath = "/patterns/" + fullPath;
  } else if (!fullPath.startsWith("/patterns/")) {
    fullPath = "/patterns" + fullPath;
  }
  return fullPath;
}

bool PatternLoader::validateFileAccess(const String& fullPath, size_t& fileSize) {
  File file = SD.open(fullPath, FILE_READ);
  if (!file) {
    Serial.print("❌ 无法打开文件: ");
    Serial.println(fullPath);
    return false;
  }
  
  // 检查文件大小 - 防止内存溢出
  fileSize = file.size();
  
  // 🔧 优化：减少详细调试输出
  static unsigned long lastSizeReport = 0;
  if (millis() - lastSizeReport > STATUS_UPDATE_INTERVAL) {
    Serial.printf("📊 文件大小: %zu bytes (%.1f KB)\n", fileSize, fileSize / 1024.0);
    lastSizeReport = millis();
  }
  
  file.close();
  return true;
}

bool PatternLoader::readJsonFromFileOptimized(const String& filePath, StaticJsonDocument<JSON_DOC_SIZE>& doc) {
  File configFile = SD.open(filePath, FILE_READ);
  if (!configFile) {
    Serial.printf("❌ 无法打开文件: %s\n", filePath.c_str());
    return false;
  }
  
  size_t size = configFile.size();
  if (size == 0) {
    Serial.println("❌ 文件为空");
    configFile.close();
    return false;
  }
  
  if (size > JSON_DOC_SIZE - 512) {  // 预留512字节缓冲
    Serial.printf("⚠️ JSON文件太大 (%d bytes)，超出限制 (%d bytes)\n", size, JSON_DOC_SIZE);
    configFile.close();
    return false;
  }
  
  Serial.printf("📖 读取JSON文件: %s (%d bytes)\n", filePath.c_str(), size);
  
  // 🔧 检查当前可用内存
  size_t freeHeapBefore = ESP.getFreeHeap();
  Serial.printf("🔍 JSON解析前可用内存: %d bytes\n", freeHeapBefore);
  
  // 🔧 优化：使用流式读取，避免大量内存分配
  DeserializationError error = deserializeJson(doc, configFile);
  configFile.close();
  
  if (error) {
    Serial.printf("❌ JSON解析失败: %s\n", error.c_str());
    if (error == DeserializationError::NoMemory) {
      size_t freeHeapAfter = ESP.getFreeHeap();
      Serial.printf("💾 内存诊断: 解析前=%d bytes, 解析后=%d bytes\n", freeHeapBefore, freeHeapAfter);
      Serial.printf("💾 建议: 文件太大(%d bytes)，请精简playlist.json或增加内存\n", size);
    }
    return false;
  }
  
  return true;
}

bool PatternLoader::readJsonFromFile(const String& filePath, DynamicJsonDocument& doc) {
  File configFile = SD.open(filePath, FILE_READ);
  if (!configFile) {
    return false;
  }
  
  size_t size = configFile.size();
  if (size == 0) {
    configFile.close();
    return false;
  }
  
  // 🔧 优化：使用流式读取替代内存分配
  DeserializationError error = deserializeJson(doc, configFile);
  configFile.close();
  
  return error == DeserializationError::Ok;
}

// ==================== 扫图数据加载功能 ====================

bool PatternLoader::loadSweepPattern(const void* sweepPoints, int totalPoints) {
  Serial.println("🔄 加载扫图数据到PatternLoader...");
  
  if (!sweepPoints || totalPoints <= 0) {
    Serial.println("❌ 扫图数据无效");
    return false;
  }
  
  // 清空当前图案
  currentPattern.clear();
  currentPatternName = "SWEEP_PATTERN";
  
  // 类型转换：将外部扫图点结构转换为PatternPoint
  struct SweepPoint {
    float theta;
    float rho;
  };
  
  const SweepPoint* points = (const SweepPoint*)sweepPoints;
  
  // 预分配内存提高性能
  currentPattern.reserve(totalPoints);
  
  // 复制扫图数据到currentPattern
  for (int i = 0; i < totalPoints; i++) {
    PatternPoint point;
    point.theta = points[i].theta;
    point.rho = points[i].rho;
    currentPattern.push_back(point);
  }
  
  // 重置流式加载状态
  isStreamMode = false;  // 扫图使用内存模式，不是流式模式
  globalIndex = 0;
  totalPointsProcessed = 0;
  bufferIndex = 0;
  buffer.clear();
  
  Serial.printf("✅ 扫图数据加载完成：%d个极坐标点\n", totalPoints);
  Serial.printf("📍 扫图范围: θ[%.3f→%.3f], ρ[%.3f→%.3f]\n", 
                points[0].theta, points[totalPoints-1].theta,
                points[0].rho, points[totalPoints-1].rho);
  
  return true;
}

// ==================== 进度报告优化函数 ====================

void PatternLoader::optimizedProgressReport(int current, int total, const String& operation) {
  static unsigned long lastProgressReport = 0;
  
  // 每隔PROGRESS_REPORT_INTERVAL毫秒报告一次进度
  if (millis() - lastProgressReport > PROGRESS_REPORT_INTERVAL) {
    float progress = (float)current / total * 100.0;
    Serial.printf("⏳ %s进度: %d/%d (%.1f%%)\n", 
                  operation.c_str(), current, total, progress);
    lastProgressReport = millis();
  }
}

// 🔧 新增：智能更新播放列表（只添加新文件，不删除用户配置）
void PatternLoader::updatePlaylistWithNewFiles() {
  Serial.println("🔄 检查是否有新的.thr文件需要添加到播放列表...");
  
  // 🔧 检查内存是否足够
  size_t freeHeap = ESP.getFreeHeap();
  Serial.printf("🔍 更新播放列表 - 可用内存: %d bytes\n", freeHeap);
  
  if (freeHeap < 10240) {  // 小于10KB时跳过更新
    Serial.println("⚠️ 内存不足，跳过播放列表更新");
    return;
  }
  
  // 读取当前的播放列表（使用堆分配避免栈溢出）
  StaticJsonDocument<JSON_DOC_SIZE>* doc = new StaticJsonDocument<JSON_DOC_SIZE>();
  if (!doc) {
    Serial.println("❌ 无法分配内存读取播放列表");
    return;
  }
  
  if (!readJsonFromFileOptimized("/playlist.json", *doc)) {
    Serial.println("❌ 无法读取现有播放列表，跳过更新");
    delete doc;
    return;
  }
  
  // 获取播放列表中已有的文件名
  std::vector<String> existingFilesInPlaylist;
  JsonArray patternArray;
  
  if (doc->is<JsonArray>()) {
    patternArray = doc->as<JsonArray>();
  } else if (doc->is<JsonObject>() && doc->containsKey("patterns")) {
    patternArray = (*doc)["patterns"].as<JsonArray>();
  } else {
    Serial.println("❌ 播放列表格式无法识别，跳过更新");
    delete doc;
    return;
  }
  
  // 提取播放列表中现有的文件名
  for (JsonVariant item : patternArray) {
    if (item.is<JsonObject>()) {
      JsonObject obj = item.as<JsonObject>();
      String filename = "";
      
      if (obj.containsKey("file_name")) {
        filename = obj["file_name"].as<String>();
      } else if (obj.containsKey("id")) {
        String id = obj["id"].as<String>();
        filename = id + ".thr";
      }
      
      if (filename.length() > 0) {
        existingFilesInPlaylist.push_back(filename);
      }
    }
  }
  
  Serial.printf("📋 播放列表中现有 %d 个文件\n", existingFilesInPlaylist.size());
  
  // 扫描SD卡中实际存在的.thr文件
  std::vector<String> actualFiles = scanForExistingThrFiles();
  Serial.printf("💾 SD卡中实际有 %d 个.thr文件\n", actualFiles.size());
  
  // 找出需要添加的新文件（在SD卡中存在但播放列表中没有的）
  std::vector<String> newFiles;
  for (const String& actualFile : actualFiles) {
    bool found = false;
    for (const String& playlistFile : existingFilesInPlaylist) {
      if (actualFile == playlistFile) {
        found = true;
        break;
      }
    }
    if (!found) {
      newFiles.push_back(actualFile);
    }
  }
  
  if (newFiles.empty()) {
    Serial.println("✅ 没有新文件需要添加，播放列表保持不变");
    delete doc;
    return;
  }
  
  Serial.printf("🆕 发现 %d 个新文件需要添加到播放列表:\n", newFiles.size());
  for (const String& newFile : newFiles) {
    Serial.printf("  + %s\n", newFile.c_str());
  }
  
  // 创建更新后的播放列表（保留原有文件 + 添加新文件）
  // 这里重新创建整个JSON数组，保持现有项目不变，只添加新项目
  File writeFile = SD.open("/playlist.json", FILE_WRITE);
  if (!writeFile) {
    Serial.println("❌ 无法打开playlist.json进行更新");
    return;
  }
  
  writeFile.println("[");
  
  // 首先写入现有的播放列表项目（保持用户配置）
  int totalItems = 0;
  for (JsonVariant item : patternArray) {
    if (item.is<JsonObject>()) {
      JsonObject obj = item.as<JsonObject>();
      
      // 保持原有项目的完整信息
      if (totalItems > 0) {
        writeFile.println(",");
      }
      
      writeFile.printf("  {\n");
      
      // 复制原有的所有字段
      if (obj.containsKey("id")) {
        writeFile.printf("    \"id\": \"%s\"", obj["id"].as<String>().c_str());
      }
      
      if (obj.containsKey("pattern_file")) {
        if (obj.containsKey("id")) writeFile.printf(",\n");
        writeFile.printf("    \"pattern_file\": \"%s\"", obj["pattern_file"].as<String>().c_str());
      }
      
      if (obj.containsKey("file_name")) {
        if (obj.containsKey("id") || obj.containsKey("pattern_file")) writeFile.printf(",\n");
        writeFile.printf("    \"file_name\": \"%s\"", obj["file_name"].as<String>().c_str());
      }
      
      writeFile.printf("\n  }");
      totalItems++;
    }
  }
  
  // 然后添加新发现的文件
  for (const String& newFile : newFiles) {
    if (totalItems > 0) {
      writeFile.println(",");
    }
    
    String id = newFile;
    if (id.endsWith(".thr")) {
      id = id.substring(0, id.length() - 4);
    }
    
    writeFile.printf("  {\n");
    writeFile.printf("    \"id\": \"%s\",\n", id.c_str());
    writeFile.printf("    \"file_name\": \"%s\"\n", newFile.c_str());
    writeFile.printf("  }");
    totalItems++;
  }
  
  writeFile.println("\n]");
  writeFile.close();
  
  Serial.printf("✅ 播放列表更新完成，总计 %d 个图案文件\n", totalItems);
  Serial.println("💡 用户的播放列表配置已保留，仅添加新发现的文件");
  
  delete doc;  // 释放内存
}

// 🔧 新增：强制重新生成播放列表（用于命令行调用）
void PatternLoader::regeneratePlaylist() {
  Serial.println("🔄 强制重新生成播放列表...");
  
  // 删除现有的播放列表文件
  if (SD.exists("/playlist.json")) {
    Serial.println("🗑️ 删除现有播放列表文件");
    SD.remove("/playlist.json");
  }
  
  // 重新创建播放列表
  Serial.println("📋 扫描SD卡创建新的播放列表...");
  
  // 扫描现有的.thr文件
  std::vector<String> existingFiles = scanForExistingThrFiles();
  
  if (existingFiles.empty()) {
    Serial.println("❌ 未找到任何.thr文件，无法创建播放列表");
    return;
  }
  
  // 创建并写入playlist.json文件
  File writeFile = SD.open("/playlist.json", FILE_WRITE);
  if (!writeFile) {
    Serial.println("❌ 无法创建playlist.json文件");
    return;
  }
  
  writeFile.println("[");
  for (int i = 0; i < existingFiles.size(); i++) {
    String filename = existingFiles[i];
    // 去掉.thr扩展名作为ID
    String id = filename;
    if (id.endsWith(".thr")) {
      id = id.substring(0, id.length() - 4);
    }
    
    writeFile.printf("  {\n");
    writeFile.printf("    \"id\": \"%s\",\n", id.c_str());
    writeFile.printf("    \"file_name\": \"%s\"\n", filename.c_str());
    writeFile.printf("  }%s\n", (i < existingFiles.size() - 1) ? "," : "");
  }
  writeFile.println("]");
  writeFile.close();
  
  Serial.printf("✅ 播放列表重新生成完成，包含 %d 个图案\n", existingFiles.size());
  Serial.println("💡 提示：新的播放列表已覆盖旧配置");
}